
#include <cstdio>
#include <BOpenGL>

#include "member_BProgram.h"

using namespace BWE;

member_BProgram::member_BProgram(BProgram* program)
{
	boss = program;
	object = 0;
	dirty = false;
	used = false;
}
member_BProgram::~member_BProgram()
{

}

bool member_BProgram::use()
{
	if (dirty)
	{
		if (!object)
			object = glCreateProgram();
		if (!object)
			return false;
		for (auto it = shaders.begin(); it != shaders.end(); ++it)
		{
			BShader* shader = *it;
			if (!shader_member(shader)->dirty)
				continue;
			if (!shader_member(shader)->compile())
				return false;
		}
		for (auto it = shaders.begin(); it != shaders.end(); ++it)
		{
			BShader* shader = *it;
			glAttachShader(object, shader_member(shader)->object);
			if (!BOpenGL::Check())
				return false;
		}
		glLinkProgram(object);
		if (!BOpenGL::Check())
			return false;
		GLint linkStatus;
		glGetProgramiv(object, GL_LINK_STATUS, &linkStatus);
		if (linkStatus != GL_TRUE)
		{
			GLint length = 0;
			glGetProgramiv(object, GL_INFO_LOG_LENGTH, &length);
			if (length > 0)
			{
				BString linkLog('*', length);
				glGetProgramInfoLog(object, length, NULL, (char*)linkLog.cstr());
				printf("Link Program faild - %s : \n", boss->name().cstr());
				puts(linkLog.cstr());
			}
			return false;
		}
		dirty = false;
	}

	if (!object)
		return false;

	glUseProgram(object);
	if (!BOpenGL::Check())
		return false;

	used = true;
	for (int i = 0; i < uniforms.size(); i++)
	{
		BUniform* uniform = uniforms[i];
		if (uniform_member(uniform)->location < 0)
		{
			uniform_member(uniform)->location = glGetUniformLocation(object, uniform->name().cstr());
		}
		uniform->flush();
	}
	return true;
}
bool member_BProgram::unuse()
{
	if (object && used)
	{
		used = false;
		glUseProgram(0);
		return true;
	}
	return false;
}
